package com.caowj.imageloader.cache2;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;

/**
 * Copyright (c) 2018 All Rights Reserved
 * <p>
 * 作者：马彦虎  Email：1184265546@qq.com
 * 创建时间： 2019/3/18.
 * 修改历史:
 * 修改日期         作者        版本        描述说明
 * </p>
 */

public class ImageFileCache {
    //SD卡缓存目录 "/sdcard/Android/data/<application package>/cache";  这样的缓存目录会跟着App的卸载而删除
    private static  String CACHDIR ;
    //缓存文件后缀
    private static final String WHOLESALE_CONV = ".cache";
    
    private static final int MB = 1024*1024;
    //缓存最大容量
    private static final int CACHE_SIZE = 100;
    //当新增一个图片时，我们需要的SD卡最少容量
    private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;
    
    public ImageFileCache(Context context) {
        String packageName=context.getPackageName();
        CACHDIR="/Android/data/"+packageName+"/cache";
    }
    
    /** 从缓存中获取图片 **/
    public Bitmap getImage(final String url) {
        final String path = getDirectory() + "/" + convertUrlToFileName(url);
        System.out.println(path);
        File file = new File(path);
        if (file.exists()) {
            Bitmap bmp = BitmapFactory.decodeFile(path);
            if (bmp == null) {
                file.delete();
            } else {
                updateFileTime(path);
                return bmp;
            }
        }
        return null;
    }
    
   
    
    /** 将图片存入文件缓存 **/
    public String saveBitmap(InputStream inputStream, String url) {
        if (inputStream == null) {
            return null;
        }
        boolean isOk= removeCache(getDirectory());
        //清完以后容量还不够，就不存了
        if (!isOk) {
            return null;
            
        }
        
        
        String filename = convertUrlToFileName(url);
        String dir = getDirectory();
        File dirFile = new File(dir);
        if (!dirFile.exists()){
            dirFile.mkdirs();
        }
           
        File file = new File(dir +"/" + filename);
        
        try {
            file.createNewFile();
            FileOutputStream fos=new FileOutputStream(file);
            try {
               
                byte[] bs=new byte[1024*100];
                int total=0;
                while ((total=inputStream.read(bs))!=-1){
                    fos.write(bs,0,total);
                }
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            fos.flush();
            fos.close();
            removeCache(getDirectory());
        } catch (FileNotFoundException e) {
            Log.w("ImageFileCache", "FileNotFoundException");
        } catch (IOException e) {
            Log.w("ImageFileCache", "IOException");
        }
        
        return file.getAbsolutePath();
    }
    /**
     * 计算存储目录下的文件大小，
     * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDE的D_TO_CACHE规定
     * 那么删除40%最近没有被使用的文件
     */
    private boolean removeCache(String dirPath) {
        File dir = new File(dirPath);
        File[] files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.getName().endsWith(WHOLESALE_CONV);
            }
        });
        if (!Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            return false;
        }
        if (files == null) {
            return true;
        }
    
        //计算缓存目录现在的使用量
        int dirSize = 0;
        for (int i = 0; i < files.length; i++) {
            if (files[i].getName().contains(WHOLESALE_CONV)) {
                dirSize += files[i].length();
            }
        }
        //判读是否已经超限
        if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            //删多少 ---removeFactor
            int removeFactor = (int) ((0.4 * files.length) + 1);
            
            //把数组中的文件---即全部缓存文件，根据最后修改时间来排序
            Arrays.sort(files, new FileLastModifSort());
            for (int i = 0; i < removeFactor; i++) {
                if (files[i].getName().contains(WHOLESALE_CONV)) {
                    files[i].delete();
                }
            }
        }
        
        if (freeSpaceOnSd() < FREE_SD_SPACE_NEEDED_TO_CACHE) {
            return false;
        }
        
        return true;
    }
    
    /** 修改文件的最后修改时间   LRU **/
    public void updateFileTime(String path) {
        File file = new File(path);
        long newModifiedTime = System.currentTimeMillis();
        file.setLastModified(newModifiedTime);
    }
    
    /** 计算sdcard上的剩余空间 **/
    private int freeSpaceOnSd() {
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;
        return (int) sdFreeMB;
    }
    
    /** 将url转成文件名 **/
    private String convertUrlToFileName(String url) {
        
        return url.hashCode() + WHOLESALE_CONV;
    }
    
    /** 获得缓存目录 **/
    private String getDirectory() {
        String dir = getSDPath() + "/" + CACHDIR;
        return dir;
    }
    
    /** 取SD卡路径 **/
    private String getSDPath() {
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED);  //判断sd卡是否存在
        if (sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();  //获取根目录
        }
        if (sdDir != null) {
            return sdDir.toString();
        } else {
            return "";
        }
    }
    
    /**
     * 根据文件的最后修改时间进行排序
     */
    private class FileLastModifSort implements Comparator<File> {
        public int compare(File arg0, File arg1) {
            if (arg0.lastModified() > arg1.lastModified()) {
                return 1;
            } else if (arg0.lastModified() == arg1.lastModified()) {
                return 0;
            } else {
                return -1;
            }
        }
    }
    
}